from django.utils import timezone  # django转换UTC时间为本地时间
from kubernetes.client.rest import ApiException
from kubernetes import client
from systemd.models import registryInfo
from ..models import ProductionDeployRecord


class ProductionOprationDeploymentApi():
    '''操作deployment'''

    def __init__(self, port=None, tag=None, namespace=None, deployment_name=None):
        self.port = port
        self.tag = tag
        self.namespace = namespace
        self.deployment_name = deployment_name
        from kubernetes import config
        config.load_kube_config(config_file="./kube_conf/product.conf")
        self.coreApi_v1 = client.CoreV1Api()
        self.extensions_v1beta1 = client.AppsV1Api()

    def get_deployment_api(self):
        '''获取deployment列表'''

        try:
            deployment_res = self.extensions_v1beta1.list_namespaced_deployment(namespace=self.namespace,
                                                                                async_req=True).get()
        except ApiException as e:
            return {'code': 500, 'msg': f'deployment列表获取失败,{str(e)}'}
        else:
            results = []
            for deployment in deployment_res.items:
                deployments = {}
                deployments['name'] = deployment.metadata.name
                deployments['replicas'] = '{}/{}'.format(deployment.status.ready_replicas, deployment.spec.replicas)
                deployments['read_replicas'] = deployment.status.ready_replicas
                deployments['create_time'] = timezone.localtime(deployment.metadata.creation_timestamp).strftime(
                    "%Y-%m-%d %H:%M:%S")

                for conditions in deployment.status.conditions:
                    deployments['status'] = conditions.status.lower()
                    deployments['message'] = conditions.message
                    deployments['update_time'] = timezone.localtime(conditions.last_update_time).strftime(
                        "%Y-%m-%d %H:%M:%S")
                for containers_spec in deployment.spec.template.spec.containers:
                    if ':' in containers_spec.image:
                        deployments['tag'] = containers_spec.image.split(':')[1]
                    else:
                        deployments['tag'] = containers_spec.image
                    deployments['image'] = containers_spec.image
                results.append(deployments)
            return results

    def get_deployment_name_api(self):
        '''获取namespace对应所有deployment名称'''

        try:
            deployment_res = self.extensions_v1beta1.list_namespaced_deployment(namespace=self.namespace,
                                                                                async_req=True).get()
        except ApiException as e:
            return {'code': 500, 'msg': 'deployment列表获取失败'}
        else:
            # 此处仅获取deployment名称
            results = [deployment.metadata.name for deployment in deployment_res.items]
            return results

    def delete_deployment_api(self):
        '''删除deployment，将整个关联的容器组全部删除'''

        try:
            Body = client.V1DeleteOptions(
                propagation_policy='Foreground',
                grace_period_seconds=3
            )
            self.extensions_v1beta1.delete_namespaced_deployment(name=self.deployment_name, namespace=self.namespace,
                                                                 body=Body, async_req=True).get()
        except ApiException as e:
            return f"{'code': 500, 'msg': 'deployment {self.deployment_name} 删除失败，{e}'}"
        else:
            return {'msg': f'deployment {self.deployment_name} 删除成功'}

    def create_deployment_obj_api(self, replicas=1):
        '''创建deployment对象'''

        registry = registryInfo.objects.filter(env=self.namespace).values('registry', 'namespace').first()
        spec_container = client.V1Container(
            name=self.deployment_name,
            image_pull_policy='Always',
            image=f"{registry.get('registry')}/{registry.get('namespace')}/{self.deployment_name}:{self.tag}",
            ports=[client.V1ContainerPort(container_port=int(self.port))],
            volume_mounts=[client.V1VolumeMount(name="log", mount_path="/var/logs"),
                           client.V1VolumeMount(name="localtime", mount_path="/etc/localtime")],
            env=[client.V1EnvVar(name="env", value=self.namespace),
                 client.V1EnvVar(name="TZ", value="Asia/Shanghai"),
                 ],
            resources=client.V1ResourceRequirements(
                limits={"memory": "2Gi"},
                requests={"memory": "1Gi"},
            ),
            readiness_probe=client.V1Probe(
                tcp_socket={
                    'port': self.port
                },
                initial_delay_seconds=35,
                period_seconds=5
            ),
            liveness_probe=client.V1Probe(
                tcp_socket={
                    'port': self.port
                },
                initial_delay_seconds=35,
                period_seconds=3
            )
        ),
        spec_volumes = [
                           client.V1Volume(name="log",
                                           host_path=client.V1HostPathVolumeSource(
                                               path=f"/var/log/apps/{self.namespace}")),
                           client.V1Volume(name="localtime",
                                           host_path=client.V1HostPathVolumeSource(path="/etc/localtime"))
                       ],
        # spec_initContainers = [
        #                           client.V1Container({
        #                               'command': [
        #                                   '/bin/sh',
        #                                   '-c',
        #                                   'mount -o remount rw /proc/sys',
        #                                   'sysctl -w net.core.somaxconn=65535',
        #                                   'sysctl -w net.ipv4.ip_local_port_range="1024 65535"',
        #                                   'sysctl -w net.core.netdev_max_backlog=8096',
        #                                   'sysctl -w net.core.rmem_default=6291456',
        #                                   'sysctl -w net.core.wmem_default=6291456',
        #                                   'sysctl -w net.core.rmem_max=12582912',
        #                                   'sysctl -w net.core.wmem_max=12582912',
        #                                   'sysctl -w fs.file-max=1048576',
        #                                   'sysctl -w net.ipv4.tcp_keepalive_time=600',
        #                                   'sysctl -w net.ipv4.tcp_max_syn_backlog=8192',
        #                                   'sysctl -w net.ipv4.tcp_max_tw_buckets=5000',
        #                                   'sysctl -w net.ipv4.tcp_syncookies=1',
        #                                   'sysctl -w net.ipv4.tcp_tw_reuse=1',
        #                                   'sysctl -w net.ipv4.tcp_tw_recycle=1',
        #                                   'sysctl -w net.ipv4.tcp_fin_timeout=30',
        #                                   'sysctl -w fs.inotify.max_user_instances=16384',
        #                                   'sysctl -w fs.inotify.max_user_watches=524288',
        #                                   'sysctl -w fs.inotify.max_queued_events=16384'
        #                               ],
        #                               'image': 'busybox',
        #                               'image_pull_policy': 'IfNotPresent',
        #                               'name': 'init-sysctl',
        #                               'security_context': client.V1SecurityContext(privileged=True)
        #                           })
        #                       ],
        template = client.V1PodTemplateSpec(
            metadata=client.V1ObjectMeta(labels={"name": self.deployment_name}),
            spec=client.V1PodSpec(containers=[spec_container], volumes=[spec_volumes],
                                  image_pull_secrets=[client.V1LocalObjectReference(name='regsecret')],
                                  # init_containers=[spec_initContainers]
                                  )
        ),
        spec = client.ExtensionsV1beta1DeploymentSpec(
            replicas=replicas,
            template=template,
            selector=client.V1LabelSelector(match_labels={"name": self.deployment_name}),
            strategy=client.ExtensionsV1beta1DeploymentStrategy(
                type='RollingUpdate',
                rolling_update=client.ExtensionsV1beta1RollingUpdateDeployment(max_surge=1, max_unavailable=1)
            ),
            min_ready_seconds=3
        )
        deployment = client.ExtensionsV1beta1Deployment(
            api_version="extensions/v1beta1",
            kind="Deployment",
            metadata=client.V1ObjectMeta(name=self.deployment_name, namespace=self.namespace),
            spec=spec)
        return deployment

    def create_deployment_api(self, replicas=1):
        '''创建deployment'''

        try:
            self.extensions_v1beta1.create_namespaced_deployment(
                namespace=self.namespace, body=self.create_deployment_obj_api(), async_req=True
            )
        except ApiException as e:
            return {'code': 500, 'msg': f'deployment {self.deployment_name} 创建失败,{str(e)}.'}
        else:
            createRecord = ProductionDeployRecord(name=self.deployment_name, env=self.namespace, tag=self.tag)
            createRecord.save()
            return {'msg': f'deployment {self.deployment_name} 创建成功!'}

    def update_deployment_api(self, update_type):
        '''更新deployoment'''

        registry = registryInfo.objects.filter(env=self.namespace).values('registry', 'namespace').first()
        image = f"{registry.get('registry')}/{registry.get('namespace')}/{self.deployment_name}:{self.tag}"
        self.create_deployment_obj_api().spec.template.spec.containers[0].image = image
        try:
            self.extensions_v1beta1.patch_namespaced_deployment(
                namespace=self.namespace, name=self.deployment_name, body=self.create_deployment_obj_api(),
                async_req=True
            ).get()
        except ApiException as e:
            return {'code': 500, 'msg': f'deployment {self.deployment_name} 更新失败，{str(e)}'}
        else:
            # 如果是回滚操作，则不作记录
            if update_type == 'update':
                createRecord = ProductionDeployRecord(name=self.deployment_name, env=self.namespace, tag=self.tag)
                createRecord.save()
            return {'msg': f'deployment {self.deployment_name} 更新成功!'}
